import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
import { MavenArtifact, ClassInfo } from './types.js';
import { ClassFinder } from './class-finder.js';
import { StreamingIndexManager, ClassIndexEntry } from './streaming-index-manager.js';

export interface LocalArtifact extends MavenArtifact {
  localPath: string;
  lastModified: Date;
  size: number;
}

export class LocalRepository {
  private classFinder: ClassFinder;
  private localRepoPath: string;
  private cache = new Map<string, LocalArtifact[]>();
  private indexManager: StreamingIndexManager;
  private repositoryIndex: Map<string, ClassIndexEntry[]> | null = null;

  constructor(classFinder: ClassFinder) {
    this.classFinder = classFinder;
    this.localRepoPath = this.getDefaultLocalRepoPath();
    this.indexManager = new StreamingIndexManager(classFinder);
  }

  private getDefaultLocalRepoPath(): string {
    const userHome = os.homedir();
    return path.join(userHome, '.m2', 'repository');
  }

  setLocalRepositoryPath(repoPath: string): void {
    this.localRepoPath = repoPath;
    this.cache.clear();
    this.repositoryIndex = null; // Clear cached index when repository path changes
  }

  getLocalRepositoryPath(): string {
    return this.localRepoPath;
  }

  async scanLocalRepository(): Promise<LocalArtifact[]> {
    console.error(`[LocalRepository] 扫描本地仓库路径: ${this.localRepoPath}`);
    
    const cacheKey = this.localRepoPath;
    if (this.cache.has(cacheKey)) {
      console.error(`[LocalRepository] 使用缓存数据`);
      return this.cache.get(cacheKey)!;
    }

    const artifacts: LocalArtifact[] = [];
    
    try {
      // 先检查路径是否存在
      try {
        const stats = await fs.stat(this.localRepoPath);
        console.error(`[LocalRepository] 仓库路径存在: ${stats.isDirectory() ? '目录' : '文件'}`);
      } catch (statError) {
        console.error(`[LocalRepository] 仓库路径不存在或无法访问: ${statError}`);
        return [];
      }
      
      console.error(`[LocalRepository] 开始扫描目录...`);
      await this.scanDirectory(this.localRepoPath, artifacts);
      
      console.error(`[LocalRepository] 扫描完成，找到 ${artifacts.length} 个artifact`);
      this.cache.set(cacheKey, artifacts);
      return artifacts;
    } catch (error) {
      console.error(`[LocalRepository] 扫描本地仓库失败 ${this.localRepoPath}: ${error}`);
      return [];
    }
  }

  async initializeIndex(): Promise<void> {
    console.error(`[LocalRepository] 初始化仓库索引...`);

    // Try to load existing index
    this.repositoryIndex = await this.indexManager.loadIndex(this.localRepoPath);
    
    if (this.repositoryIndex) {
      const stats = await this.indexManager.getIndexStats(this.localRepoPath);
      console.error(`[LocalRepository] 成功加载现有索引，包含 ${stats?.totalClasses || 0} 个类`);
      return;
    }

    // Generate new index
    console.error(`[LocalRepository] 索引不存在或已过期，开始生成新索引...`);
    const artifacts = await this.scanLocalRepository();
    
    if (artifacts.length === 0) {
      console.error(`[LocalRepository] 没有找到artifact，跳过索引生成`);
      return;
    }

    console.error(`[LocalRepository] 开始流式索引生成，这可能需要几分钟时间...`);
    this.repositoryIndex = await this.indexManager.generateIndex(this.localRepoPath, artifacts);
    console.error(`[LocalRepository] 索引初始化完成`);
  }

  async findClassesByName(className: string): Promise<ClassIndexEntry[]> {
    // Ensure index is initialized
    if (!this.repositoryIndex) {
      await this.initializeIndex();
    }

    if (!this.repositoryIndex) {
      console.error(`[LocalRepository] 索引未初始化，无法搜索类`);
      return [];
    }

    console.error(`[LocalRepository] 使用索引搜索类: ${className}`);
    return this.indexManager.searchClasses(this.repositoryIndex, className);
  }

  async findClassesByFullName(fullClassName: string): Promise<ClassIndexEntry[]> {
    // Ensure index is initialized
    if (!this.repositoryIndex) {
      await this.initializeIndex();
    }

    if (!this.repositoryIndex) {
      console.error(`[LocalRepository] 索引未初始化，无法搜索类`);
      return [];
    }

    // Search for exact full class name match
    const lowerFullName = fullClassName.toLowerCase();
    const results: ClassIndexEntry[] = [];
    
    // Direct lookup for exact match
    if (this.repositoryIndex.has(lowerFullName)) {
      const matches = this.repositoryIndex.get(lowerFullName)!;
      for (const match of matches) {
        if (match.fullName === fullClassName) {
          results.push(match);
        }
      }
    }
    
    console.error(`[LocalRepository] 精确匹配 '${fullClassName}' 找到 ${results.length} 个结果`);
    return results;
  }

  private async scanDirectory(dir: string, artifacts: LocalArtifact[], groupParts: string[] = []): Promise<void> {
    try {
      const entries = await fs.readdir(dir, { withFileTypes: true });
      console.error(`[LocalRepository] 扫描目录 ${dir}，包含 ${entries.length} 个条目，当前groupParts: [${groupParts.join(', ')}]`);
      
      let dirCount = 0;
      let versionDirCount = 0;
      
      for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);
        
        if (entry.isDirectory()) {
          dirCount++;
          if (await this.isVersionDirectory(entry.name, fullPath)) {
            console.error(`[LocalRepository] 发现版本目录: ${entry.name}`);
            versionDirCount++;
            await this.scanVersionDirectory(fullPath, groupParts, entry.name, artifacts);
          } else {
            await this.scanDirectory(fullPath, artifacts, [...groupParts, entry.name]);
          }
        }
      }
      
      console.error(`[LocalRepository] 目录 ${dir} 扫描完成: ${dirCount} 个子目录, ${versionDirCount} 个版本目录`);
    } catch (error) {
      console.error(`[LocalRepository] 无法读取目录 ${dir}: ${error}`);
    }
  }

  private async isVersionDirectory(name: string, fullPath: string): Promise<boolean> {
    console.error(`[LocalRepository] 检查是否为版本目录: ${name} at ${fullPath}`);
    
    // Improved version pattern to match various Maven version formats
    // Examples: 1.0, 1.0.0, 1.0-SNAPSHOT, 1.24.0.RELEASE, 2.7.7, etc.
    const versionPattern = /^\d+(\.\d+)*([.-][A-Za-z0-9]+)*$/;
    
    if (!versionPattern.test(name)) {
      console.error(`[LocalRepository] ${name} 不匹配版本格式`);
      return false;
    }

    // Check if this directory contains POM or JAR files
    try {
      const files = await fs.readdir(fullPath);
      console.error(`[LocalRepository] 版本目录 ${name} 包含文件: [${files.join(', ')}]`);
      
      const hasArtifactFiles = files.some(file => file.endsWith('.pom') || file.endsWith('.jar'));
      console.error(`[LocalRepository] ${name} ${hasArtifactFiles ? '是' : '不是'}版本目录`);
      
      return hasArtifactFiles;
    } catch {
      console.error(`[LocalRepository] 无法读取目录 ${fullPath}`);
      return false;
    }
  }

  private async scanVersionDirectory(
    versionDir: string, 
    groupParts: string[], 
    version: string, 
    artifacts: LocalArtifact[]
  ): Promise<void> {
    try {
      const files = await fs.readdir(versionDir);
      const jarFiles = files.filter(file => file.endsWith('.jar') && !file.endsWith('-sources.jar') && !file.endsWith('-javadoc.jar'));
      
      // Extract artifactId and groupId from path structure
      // For path like: /repository/12345/1.24.0.RELEASE/srm-starter-core-1.24.0.RELEASE.jar
      // groupParts would be: [12345, 1.24.0.RELEASE] 
      const artifactId = groupParts.length > 0 ? groupParts[groupParts.length - 2] : 'unknown';
      const groupId = groupParts.length > 1 ? groupParts.slice(0, -2).join('.') : (groupParts[0] || 'unknown');
      
      console.error(`[LocalRepository] 解析得到 - groupId: "${groupId}", artifactId: "${artifactId}"`);
      
      // If groupParts structure doesn't make sense, try to infer from JAR filename
      let finalGroupId = groupId;
      let finalArtifactId = artifactId;
      
      if (!jarFiles.length) {
        console.error(`[LocalRepository] 没有找到JAR文件，跳过此目录`);
        return;
      }
      
      // Try to extract better artifact info from the first JAR filename
      const firstJar = jarFiles[0];
      const jarBaseName = firstJar.replace(/\.jar$/, '');
      
      // Try to match pattern: artifactId-version.jar
      const versionSuffix = `-${version}`;
      if (jarBaseName.endsWith(versionSuffix)) {
        finalArtifactId = jarBaseName.slice(0, -versionSuffix.length);
        console.error(`[LocalRepository] 从JAR文件名推断出artifactId: "${finalArtifactId}"`);
      }
      
      // If groupId is still unclear, use a reasonable default
      if (!finalGroupId || finalGroupId === 'unknown') {
        finalGroupId = 'local.repository';
        console.error(`[LocalRepository] 使用默认groupId: "${finalGroupId}"`);
      }
      
      console.error(`[LocalRepository] 扫描版本目录: ${versionDir}`);
      console.error(`[LocalRepository] - 包含文件: ${files.length} 个`);
      console.error(`[LocalRepository] - JAR文件: ${jarFiles.length} 个: [${jarFiles.join(', ')}]`);
      console.error(`[LocalRepository] - 最终解析: groupId: ${finalGroupId}, artifactId: ${finalArtifactId}, version: ${version}`);
      
      for (const jarFile of jarFiles) {
        const jarPath = path.join(versionDir, jarFile);
        const stats = await fs.stat(jarPath);
        
        // Extract classifier if present (use a more flexible pattern)
        let classifier = undefined;
        const jarBaseName = jarFile.replace(/\.jar$/, '');
        const expectedPrefix = `${finalArtifactId}-${version}`;
        
        if (jarBaseName.startsWith(expectedPrefix)) {
          const remainder = jarBaseName.slice(expectedPrefix.length);
          if (remainder.startsWith('-') && remainder.length > 1) {
            classifier = remainder.slice(1); // Remove the leading '-'
          }
        }
        
        const artifact = {
          groupId: finalGroupId,
          artifactId: finalArtifactId,
          version,
          packaging: 'jar',
          classifier,
          localPath: jarPath,
          lastModified: stats.mtime,
          size: stats.size
        };
        
        artifacts.push(artifact);
        console.error(`[LocalRepository] 添加artifact: ${finalGroupId}:${finalArtifactId}:${version}${classifier ? ':' + classifier : ''} -> ${jarPath}`);
      }
    } catch (error) {
      console.error(`[LocalRepository] 扫描版本目录失败 ${versionDir}: ${error}`);
    }
  }

  async findLocalArtifact(groupId: string, artifactId: string, version?: string): Promise<LocalArtifact[]> {
    const allArtifacts = await this.scanLocalRepository();
    
    return allArtifacts.filter(artifact => {
      return artifact.groupId === groupId && 
             artifact.artifactId === artifactId &&
             (!version || artifact.version === version);
    });
  }

  async searchLocalArtifacts(query: string): Promise<LocalArtifact[]> {
    const allArtifacts = await this.scanLocalRepository();
    const lowerQuery = query.toLowerCase();
    
    return allArtifacts.filter(artifact => {
      return artifact.groupId.toLowerCase().includes(lowerQuery) ||
             artifact.artifactId.toLowerCase().includes(lowerQuery) ||
             artifact.version.toLowerCase().includes(lowerQuery);
    });
  }

  async getLocalArtifactClasses(artifact: LocalArtifact): Promise<ClassInfo[]> {
    try {
      return await this.classFinder.findClassesInJar(artifact.localPath);
    } catch (error) {
      console.error(`Failed to analyze local artifact ${artifact.localPath}: ${error}`);
      return [];
    }
  }

  async getLocalVersions(groupId: string, artifactId: string): Promise<string[]> {
    const artifacts = await this.findLocalArtifact(groupId, artifactId);
    const versions = [...new Set(artifacts.map(a => a.version))];
    return versions.sort((a, b) => this.compareVersions(a, b));
  }

  private compareVersions(a: string, b: string): number {
    const parseVersion = (version: string) => {
      return version.split(/[.-]/).map(part => {
        const num = parseInt(part, 10);
        return isNaN(num) ? part : num;
      });
    };
    
    const aParts = parseVersion(a);
    const bParts = parseVersion(b);
    const maxLength = Math.max(aParts.length, bParts.length);
    
    for (let i = 0; i < maxLength; i++) {
      const aPart = aParts[i] || 0;
      const bPart = bParts[i] || 0;
      
      if (typeof aPart === 'number' && typeof bPart === 'number') {
        if (aPart !== bPart) return bPart - aPart; // Descending order
      } else {
        const result = String(bPart).localeCompare(String(aPart));
        if (result !== 0) return result;
      }
    }
    
    return 0;
  }

  async rebuildIndex(): Promise<void> {
    console.error(`[LocalRepository] 强制重建索引...`);
    
    // Delete existing index
    await this.indexManager.deleteIndex(this.localRepoPath);
    this.repositoryIndex = null;
    this.cache.clear();
    
    // Rebuild index
    await this.initializeIndex();
  }

  async getIndexStats(): Promise<any> {
    return await this.indexManager.getIndexStats(this.localRepoPath);
  }

  isIndexReady(): boolean {
    return this.repositoryIndex !== null;
  }

  async getIndexedClassCount(): Promise<number> {
    const stats = await this.indexManager.getIndexStats(this.localRepoPath);
    return stats?.totalClasses || 0;
  }

  async getIndexedArtifactCount(): Promise<number> {
    const stats = await this.indexManager.getIndexStats(this.localRepoPath);
    return stats?.totalArtifacts || 0;
  }

  clearCache(): void {
    this.cache.clear();
    this.classFinder.clearCache();
    // Note: We don't clear repositoryIndex here as it's persistent
  }
}